import json
import re


# Create your views here.
"""
需求分析：根据页面功能（从上到下从左到右），哪些功能需要后端配合完成
如何确定 哪些功能需要和后端进行交互
        1.经验
        2.关注类似网站的相似功能
"""

"""
判断用户名是否重复
前端
    当用户输入用户名，在鼠标失去焦点后，发送ajax请求 
后端
    请求：         接收用户名
    业务逻辑：      拿到用户名后，根据用户名查询数据库，如查询结果为0，则说明用户名没有注册过；
                  查询结果等于1，则说明该用户名已经注册
    响应：         JSON数据
                  {code:0,count:0/1,errmsg:ok}
    路由:          GET  usernames/<username>/count/
    步骤：1.接收前端数据
        2.查询数据库进行判断
        3.返回响应
"""

from django.views import View
from apps.users.models import User, Address
from django.http import JsonResponse
class UsernameCountView(View):
    def get(self,requset,username):
        # import re
        # #1.接收用户名对用户名进行判断
        # if not re.match('[a-zA-Z0-9_-]{5,20}',username):
        #     return JsonResponse({'code':200,'errmsg':'用户名不满足需求'})
        #2.根据用户名查询数据库
        count=User.objects.filter(username=username).count()
        #3.返回响应
        return JsonResponse({'code':0,'count':count,'errmsg':'ok'})
        pass

"""
不相信前端提交的任何数据！！！需要在后端再次验证
前端： 当用户输入 用户名，密码，确认密码，手机号，验证码，是否同意协议
      之后，会点击注册按钮，前端发送axios请求

后端：
        请求： 接收请求，获取数据
        业务逻辑：验证数据，数据入库
        响应： JSON{'code':0,'errmsg':'ok'}
        
        路由：  POST  register
        
        
        步骤：1.接收请求
             2.获取数据
             3.验证数据
                3.1 用户名，密码，确认密码，手机号，验证码，是否同意协议 都要有
                3.2 用户名是否满足规则，用户名不能重复
                3.3 密码是否满足规则
                3.4 确认密码是否和密码一致
                3.5 手机号满足规则 ，手机号也不能重复
                3.6 是否同意协议
             4.数据入库
             5.返回响应
"""

class RegisterView(View):
    def post(self,request):
        # 1.接收请求
        body_bytes=request.body
        body_str=body_bytes.decode()
        body_dict=json.loads(body_str)
        #      2.获取数据
        username = body_dict.get('username')
        password = body_dict.get('password')
        password2 = body_dict.get('password2')
        mobile = body_dict.get('mobile')

        sms_code=body_dict.get('sms_code')

        allow = body_dict.get('allow')
        #      3.验证数据
        #         3.1 用户名，密码，确认密码，手机号，验证码，是否同意协议 都要有
        if not all([username,password,password2,mobile,allow]):
            return JsonResponse({'code':400,'errmsg':'参数不全'})
        #         3.2 用户名是否满足规则，用户名不能重复
        # import re
        if not re.match('[a-zA-Z_-]{5,20}',username):
            return JsonResponse({'code':400,'errmsg':'用户名不满足规则'})
        #         3.3 密码是否满足规则
        len_password=len(password)
        if len_password < 8 or len_password > 20:
            return JsonResponse({'code':400,'errmsg':'密码不满足规则'})
        #         3.4 确认密码是否和密码一致
        if password!=password2:
            return JsonResponse({'code':400,'errmsg':'确认密码不满足规则'})
        #         3.5 手机号满足规则 ，手机号也不能重复
        #         3.6 是否同意协议
        if not allow==True:
            return JsonResponse({'code': 400, 'errmsg': '没有同意协议'})
        #
        #


        # 判断短信验证码是否正确：跟图形验证码的验证一样的逻辑
        # 提取服务端存储的短信验证码：以前怎么存储，现在就怎么提取
        from django_redis import get_redis_connection
        redis_conn = get_redis_connection('code')
        sms_code_server = redis_conn.get(mobile)  # sms_code_server是bytes
        # 判断短信验证码是否过期
        if not sms_code_server:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码失效'})
        # 对比用户输入的和服务端存储的短信验证码是否一致
        if sms_code != sms_code_server.decode():
            return JsonResponse({'code': 400, 'errmsg': '短信验证码有误'})




        #      4.数据入库
        # user=User(username=username,password=password,mobile=mobile)
        # user.save()
        # user=User.objects.create(username=username,password=password,mobile=mobile)
        #密码加密
        user = User.objects.create_user(username=username,password=password,mobile=mobile)
        # request.session['user_id']=user.id
        #系统（Django）为我们提供了状态保持的方法
        from django.contrib.auth import login
        #状态保持已经登陆的状态保持
        #user 已经登陆的用户信息
        login(request,user)
        return JsonResponse({'code':0,'errmsg':'ok'})
        #      5.返回响应


"""
登录

前端：
        当用户把用户名和密码输入完成之后，会点登录按钮。这个时候前端应该发送axios请求

后端:
    请求：   接收前端数据，验证数据
    业务逻辑：验证用户名和密码，session
    响应：   返回JSON数据  0 成功，400 失败

步骤：
    1.接收数据
    2.验证数据
    3.验证用户名和密码
    4.session
    5.判断是否记住登录
    6.返回响应
"""


class LoginView(View):
    def post(self, request):
        # 1.接收数据
        data = json.loads(request.body.decode())
        username = data.get('username')
        password = data.get('password')
        remembered = data.get('remembered')
        # 2.验证数据
        if not all([username, password]):
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})
        # 3.验证用户名和密码
        if re.match('1[3-9]\d{9}',username):
            User.USERNAME_FIELD='mobile'
        else:
            User.USERNAME_FIELD='username'
        # 我们可以通过模型根据用户名查询
        # User.objects.get(username=username)
        # 如果用户名和密码正确，则返回User信息
        # 如果用户名和密码不正确则返回 None
        from django.contrib.auth import authenticate
        user = authenticate(username=username, password=password)
        if user is None:
            return JsonResponse({'code': 400, 'errmsg': '账号或密码不正确'})
        # 4.session
        from django.contrib.auth import login
        login(request, user)
        # 5.判断是否记住登录
        if remembered:
            # 记住登录 --2周或者一个月 具体时间产品说了算
            request.session.set_expiry(None)
        else:
            # 不记住登录  浏览器关闭 session过期
            request.session.set_expiry(0)
        # 6.返回响应
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        #为了首页显示用户信息
        response.set_cookie('username',username)



        #必须是登录后合并
        from apps.carts.utils import merge_cookie_to_redis
        response=merge_cookie_to_redis(request,response)


        return response

"""
前端：
    当用户点击退出按钮时，发送axios delete请求

后端：
    请求：     
    业务逻辑：  退出
    响应：     返回JSON数据
"""


from django.contrib.auth import logout
class LogoutView(View):
    def delete(self,request):
        #删除session信息
        logout(request)

        response = JsonResponse({'code':0,'errmsg':'ok'})
        #删除cookie信息，前端根据cookie信息来判断用户是否登录
        response.delete_cookie('username')
        return response

from uitls.views import LoginRequiredJSONMixin
class CenterView(LoginRequiredJSONMixin,View):
    def get(self,request):
        #request.user 就是已经登陆的用户信息
        #request.user 来源于中间件
        #系统会进行判断 如果我们确实是登录用户，则可以获取到登陆用户对应的 模型实例数据
        #如果我们不是登录用户，则request.user = AnonymousUser() 匿名用户
        info_data = {
            'username':request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active,
        }
        return JsonResponse({'code':0,'errmsg':'ok','info_data':info_data})


"""
需求：1.保存邮箱地址 2.发送一封激活邮件 3.用户激活邮件

前端：
    当用户输入邮箱后，点击保存。 这个时候会发送axios请求

后端：
    请求：        接收请求，获取数据
    业务逻辑：     保存邮箱地址，发送一封激活邮件
    响应          JSON  code=0
    路由          PUT
    步骤      
        1.接收请求
        2.获取数据、
        3.保存邮箱地址
        4.发送一封激活邮件
        5.返回响应

需求（要实现什么功能)-->思路（请求，业务逻辑，响应）-->步骤-->代码实现
"""
class EmailView(LoginRequiredJSONMixin,View):
    def put(self,request):
        # 1.接收请求
        data=json.loads(request.body.decode())
        # 2.获取数据、
        email=data.get('email')
        # 3.保存邮箱地址
        user=request.user
        user.email=email
        user.save()
        # 4.发送一封激活邮件
        from django.core.mail import send_mail
        # # subject,主题
        # subject='美多商城激活邮件'
        # # message,邮件内容
        # message=''
        # # from_email,发件人
        # from_email='美多商城<17262270209@163.com>'
        # # recipient_list,收件人列表
        # recipient_list = [email]
        #
        # #对a标签进行加密
        # from apps.users.uitls import generic_email_verify_token
        # token=generic_email_verify_token(request.user.id)
        # # html_message = None,发送链接
        # html_message="点击按钮激活<a href='http://www.baidu.com?token=%s'>激活</a>"%token
        # send_mail(subject=subject,message=message,from_email=from_email
        #           ,recipient_list=recipient_list,html_message=html_message)
        user_id=request.user.id
        from celery_tasks.email.tasks import celery_send_email
        token=celery_send_email.delay(email,user_id)

        # 5.返回响应
        return JsonResponse({'code':0,'errmsg':'ok'})
    #QUdUHujjg6Sb7cy4

"""
django项目
1.django的基础 夯实
2.需求分析
3.学习新知识
4.掌握分析问题，解决问题的能力
"""

"""
1.设置邮件服务器
    我们设置了163邮箱服务器
    相当于我们开启了 让163帮助我们发送邮件，同时设置了一些信息

2.设置邮箱发送的配置信息
    #让django的哪个类发送邮件
    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    #邮件服务器上的主机和端口号
    EMAIL_HOST = 'smtp.163.com'
    EMAIL_PORT = 25
    #发送邮件的邮箱
    EMAIL_HOST_USER = '17262270209@163.com'
    #在邮箱中设置的客户端授权密码
    EMAIL_HOST_PASSWORD = 'QUdUHujjg6Sb7cy4'
    
3.调用 send_mail 方法
"""

"""
需求 
    激活用户邮件
前端
    用户点击激活链接，激活链接携带token
后端  
    请求         接收请求，获取参数，验证参数
    业务逻辑      user_id,根据用户id查询数据，修改数据
    响应         返回响应JSON
    路由         PUT emails/verification/ 说明：token没有在body中
    步骤：
        1.接受请求
        2.获取参数
        3.验证参数
        4.获取user_id
        5.根据用户id查询数据
        6.修改数据
        7.返回响应JSON
"""
class EmailVerifyView(View):
    def put(self,request):
        # 1.接受请求
        params=request.GET
        # 2.获取参数
        token = params.get('token')
        # 3.验证参数
        if token is None:
            return JsonResponse({'code':400,'errmsg':'参数不全'})
        # 4.获取user_id
        from apps.users.uitls import check_verify_token
        user_id = check_verify_token(token)
        if user_id is None:
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})
        # 5.根据用户id查询数据
        user=User.objects.get(id=user_id)
        # 6.修改数据
        user.email_active=True
        user.save()
        # 7.返回响应JSON
        return JsonResponse({'code': 0, 'errmsg': 'ok'})



"""
请求
业务逻辑 （数据库的增删改查）
响应

增  （注册）
    1.接收数据
    2.验证数据
    3.数据入库
    4.返回响应
删   
    1.查询指定记录
    2.删除数据
    3.返回响应
改   （个人邮箱）
    1.查询指定数据
    2.接收数据
    3.验证数据
    4.数据更新
    5.返回响应
查   (个人中心的数据展示，省市区)
    1.查询指定数据
    2.将对象数据转换为字典数据】
    3.返回响应
"""

"""
需求
    新增地址
前端
    当用户填写完地址信息后，前端发送一个axios请求
后端
    请求      接收数据
    业务逻辑   数据入库
    响应      返回响应
    路由      POST  /addresses/create/
    步骤
        1.接受请求
        2.获取参数
        3.数据入库
        4.返回响应
"""

class AddressCreateView(LoginRequiredJSONMixin,View):
    def post(self,request):
        # 1.接受请求
        data=json.loads(request.body.decode())
        # 2.获取参数,验证参数
        receiver=data.get('receiver')
        province_id=data.get('province_id')
        city_id=data.get('city_id')
        district_id=data.get('district_id')
        place=data.get('place')
        mobile=data.get('mobile')
        tel=data.get('tel')
        email=data.get('email')
        user = request.user
        #验证参数
        # 2.1验证必传参数
        # 2.2省市区的id 是否正确
        # 2.3详细地址的长度
        # 2.4手机号
        # 2.5固定电话
        # 2.6邮箱

        # 3.数据入库
        address=Address.objects.create(
            user=user,
            title=receiver,
            receiver=receiver,
            province_id=province_id,
            city_id=city_id,
            district_id=district_id,
            place=place,
            mobile=mobile,
            tel=tel,
            email=email
        )
        address_dict={
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        # 4.返回响应
        return JsonResponse({'code':0,'errmsg':'ok','address':address_dict})

#数据展示
class AddressView(LoginRequiredJSONMixin,View):

    def get(self,request):
        user=request.user
        # addresses = user.addresses
        addresses=Address.objects.filter(user=user,is_deleted=False)
        address_list=[]
        for address in addresses:
            address_list.append({
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            })
        return JsonResponse({'code':0,'errmsg':'ok','addresses':address_list})

import logging
logger = logging.getLogger(__name__)
class UpdateDestroyAddressView(LoginRequiredJSONMixin, View):
    def put(self, request, address_id):
        """修改地址"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        #通过先查询地址对象，再修改字段修改
        # address= Address.objects.get(id=address_id)
        # address.user=request.user
        # address.title=receiver
        # address.receiver=receiver
        # address.province_id=province_id
        # address.city_id=city_id
        # address.district_id=district_id
        # address.place=place
        # address. mobile=mobile
        # address.tel=tel
        # address.email=email
        # address.save()
        #使用filter().update()方法
        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )

        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '更新地址失败'})

            # 构造响应数据
        address = Address.objects.get(id=address_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应更新地址结果
        return JsonResponse({'code': 0, 'errmsg': '更新地址成功', 'address': address_dict})

    def delete(self, request, address_id):
        """删除地址"""
        try:
            # 查询要删除的地址
            address = Address.objects.get(id=address_id)

            # 将地址逻辑删除设置为True
            address.is_deleted = True
            address.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '删除地址失败'})

        # 响应删除地址结果
        return JsonResponse({'code': 0, 'errmsg': '删除地址成功'})

class DefaultAddressView(LoginRequiredJSONMixin, View):
    """设置默认地址"""

    def put(self, request, address_id):
        """设置默认地址"""
        try:
            # 接收参数,查询地址
            address = Address.objects.get(id=address_id)

            # 设置地址为默认地址
            request.user.default_address = address
            request.user.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '设置默认地址失败'})

        # 响应设置默认地址结果
        return JsonResponse({'code': 0, 'errmsg': '设置默认地址成功'})

class UpdateTitleAddressView(LoginRequiredJSONMixin, View):
    """设置地址标题"""

    def put(self, request, address_id):
        """设置地址标题"""
        # 接收参数：地址标题
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')

        try:
            # 查询地址
            address = Address.objects.get(id=address_id)

            # 设置新的地址标题
            address.title = title
            address.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '设置地址标题失败'})

        # 4.响应删除地址结果
        return JsonResponse({'code': 0, 'errmsg': '设置地址标题成功'})



"""
一、根据页面效果，需求分析
        1.最近浏览记录 只有登录用户才可以访问 只记录登陆用户的浏览记录
        2.浏览记录有顺序
        3.没有分页
二、功能
    ①在用户访问商品详情的时候 添加浏览记录
    ②在个人中心 展示浏览记录
三、分析
    要保存商品id、用户id、顺序（访问时间）
    一般保存在数据库中（慢，需要频繁操作数据库）
    也可保存在redis中

use_id sku_id 顺序
key:value
redis :
        string x
        hash   x
        list   v
        set    x
        zset   v
            权重：值
"""
"""
添加浏览记录
    前端：
        当登录用户，访问某一个具体的SKU页面时，发送一个axios请求，请求携带 sku_id
    后端：
        请求      接受请求 获取请求参数 验证参数
        业务逻辑   连接redis 先去重 再保存到redis中 只有5条记录
        响应      返回JOSN
        路由      POST  browse_histories
        步骤
            1.接受请求
            2.获取请求参数
            3.验证参数
            4.连接 redis list
            5.去重
            6.保存到redis中
            7.只保存5条记录
            8.返回响应
展示浏览记录
    前端：
        用户在访问浏览记录的时候，发送axios请求 请求会携带session信息
    后端：
        请求      
        业务逻辑   连接redis 获取redis数据([1,2,3]) 根据商品id进行查询 将对象转换为字典
        响应      返回JOSN
        路由      GET  
        步骤
            1.连接redis
            2.获取redis数据
            3.根据商品id查询数据
            4.将对象转换为字典
            5.返回JSON
"""
from apps.goods.models import SKU
from django_redis import get_redis_connection
class UserHistoryView(LoginRequiredJSONMixin,View):
    def post(self,request):
        user = request.user

        # 1.接受请求
        data=json.loads(request.body.decode())
        # 2.获取请求参数
        sku_id=data.get('sku_id')
        # 3.验证参数
        try:
            sku=SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code':400,'errmsg':'没有此商品'})
        # 4.连接 redis list
        redis_cli=get_redis_connection('history')
        # 5.去重
        redis_cli.lrem('history_%s'%user.id,0,sku_id)
        # 6.保存到redis中
        redis_cli.lpush('history_%s' % user.id, sku_id)
        # 7.只保存5条记录
        redis_cli.ltrim('history_%s' % user.id, 0,4)
        # 8.返回响应
        return JsonResponse({'code':0,'errmsg':'ok'})

    def get(self,request):
        # 1.连接redis
        redis_cli=get_redis_connection('history')
        # 2.获取redis数据
        ids=redis_cli.lrange('history_%s'%request.user.id,0,4)
        # 3.根据商品id查询数据
        history_list=[]
        for sku_id in ids:
            # 4.将对象转换为字典
            sku=SKU.objects.get(id=sku_id)
            history_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })
        # 5.返回JSON
        return JsonResponse({'code':0,'errmsg':'ok','skus':history_list})